using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
using _3Dto2D.Configuration;
using _3Dto2D.Interfaces;
using _3Dto2D.Models;
using _3Dto2D.Services;

namespace _3Dto2D.ViewModels;

public class MainViewModel : INotifyPropertyChanged
{
    private readonly IRenderEngine _renderEngine;
    private readonly ILibraryManager _libraryManager;
    private readonly ExportService _exportService;
    private readonly ILogger<MainViewModel> _logger;
    private readonly RenderSettings _settings;

    private LibraryData? _currentLibrary;
    private LibraryData? _handLibrary;
    private int _currentFrame;
    private bool _showRefImage = true;
    private bool _showHandImage;
    private bool _blankHandImage;
    private MeshData? _currentMesh;
    private bool _isExporting;
    private string _statusMessage = "Ready";

    public MainViewModel(
        IRenderEngine renderEngine,
        ILibraryManager libraryManager,
        ExportService exportService,
        ILogger<MainViewModel> logger,
        RenderSettings settings)
    {
        _renderEngine = renderEngine;
        _libraryManager = libraryManager;
        _exportService = exportService;
        _logger = logger;
        _settings = settings;

        // Initialize default values
        BackgroundColor = _settings.BackgroundColor;
        CharacterOffsetX = _settings.CharacterGlobalOffsetX;
        CharacterOffsetY = _settings.CharacterGlobalOffsetY;
    }

    #region Properties

    public LibraryData? CurrentLibrary
    {
        get => _currentLibrary;
        set
        {
            if (SetProperty(ref _currentLibrary, value))
            {
                OnPropertyChanged(nameof(FrameCount));
                OnPropertyChanged(nameof(HasLibrary));
                CurrentFrame = 0;
            }
        }
    }

    public LibraryData? HandLibrary
    {
        get => _handLibrary;
        set => SetProperty(ref _handLibrary, value);
    }

    public int CurrentFrame
    {
        get => _currentFrame;
        set
        {
            if (SetProperty(ref _currentFrame, value))
            {
                UpdateCurrentFrameData();
            }
        }
    }

    public int FrameCount => _currentLibrary?.Frames.Count ?? 0;
    public bool HasLibrary => _currentLibrary != null;

    private FrameData? _currentFrameData;
    public FrameData? CurrentFrameData
    {
        get => _currentFrameData;
        set
        {
            if (SetProperty(ref _currentFrameData, value))
            {
                OnPropertyChanged(nameof(CurrentFrameData));
            }
        }
    }

    public bool ShowRefImage
    {
        get => _showRefImage;
        set
        {
            if (SetProperty(ref _showRefImage, value))
            {
                UpdateCurrentFrameData();
            }
        }
    }

    public bool ShowHandImage
    {
        get => _showHandImage;
        set
        {
            if (SetProperty(ref _showHandImage, value))
            {
                UpdateCurrentFrameData();
            }
        }
    }

    public bool BlankHandImage
    {
        get => _blankHandImage;
        set
        {
            if (SetProperty(ref _blankHandImage, value))
            {
                UpdateCurrentFrameData();
            }
        }
    }

    public MeshData? CurrentMesh
    {
        get => _currentMesh;
        set
        {
            if (SetProperty(ref _currentMesh, value))
            {
                OnPropertyChanged(nameof(HasMesh));
                if (CurrentLibrary == null)
                {
                    CurrentFrameData = new FrameData
                    {
                        Index = 0,
                        Mesh = _currentMesh,
                        Transform = new TransformData
                        {
                            RotationX = 355,
                            RotationY = 279,
                            RotationZ = 12,
                            MoveX = 3,
                            MoveY = -1,
                            MoveZ = 0
                        }
                    };
                }
                else
                {
                    UpdateCurrentFrameData();
                }
            }
        }
    }

    public bool HasMesh => _currentMesh?.IsLoaded == true;

    public bool IsExporting
    {
        get => _isExporting;
        set => SetProperty(ref _isExporting, value);
    }

    public string StatusMessage
    {
        get => _statusMessage;
        set => SetProperty(ref _statusMessage, value);
    }

    public Color BackgroundColor { get; set; }
    public int CharacterOffsetX { get; set; }
    public int CharacterOffsetY { get; set; }

    #endregion

    #region Commands

    public async Task LoadLibraryAsync(string filePath, bool isReference = true)
    {
        try
        {
            StatusMessage = "Loading library...";
            var library = await _libraryManager.LoadLibraryAsync(filePath, isReference);
            
            if (library != null)
            {
                CurrentLibrary = library;
                StatusMessage = $"Loaded library with {library.Frames.Count} frames";
                _logger.LogInformation("Successfully loaded library: {FilePath}", filePath);
            }
            else
            {
                StatusMessage = "Failed to load library";
                _logger.LogWarning("Failed to load library: {FilePath}", filePath);
            }
        }
        catch (Exception ex)
        {
            StatusMessage = $"Error loading library: {ex.Message}";
            _logger.LogError(ex, "Error loading library: {FilePath}", filePath);
        }
    }

    public async Task LoadHandLibraryAsync(string filePath)
    {
        try
        {
            StatusMessage = "Loading hand library...";
            var library = await _libraryManager.LoadLibraryAsync(filePath, false);
            
            if (library != null)
            {
                HandLibrary = library;
                StatusMessage = "Hand library loaded";
                _logger.LogInformation("Successfully loaded hand library: {FilePath}", filePath);
            }
            else
            {
                StatusMessage = "Failed to load hand library";
            }
        }
        catch (Exception ex)
        {
            StatusMessage = $"Error loading hand library: {ex.Message}";
            _logger.LogError(ex, "Error loading hand library: {FilePath}", filePath);
        }
    }

    public void LoadMesh(string filePath)
    {
        try
        {
            StatusMessage = "Loading mesh...";

            var mesh = new MeshData
            {
                FilePath = filePath,
                IsLoaded = true // Simplified for now
            };

            CurrentMesh = mesh;
            StatusMessage = "Mesh loaded";
            _logger.LogInformation("Successfully loaded mesh: {FilePath}", filePath);
        }
        catch (Exception ex)
        {
            StatusMessage = $"Error loading mesh: {ex.Message}";
            _logger.LogError(ex, "Error loading mesh: {FilePath}", filePath);
        }
    }

    public async Task ExportLibraryAsync(string outputPath, int startFrame = 0, int? endFrame = null)
    {
        if (CurrentLibrary == null)
        {
            StatusMessage = "No library loaded";
            return;
        }

        try
        {
            IsExporting = true;
            StatusMessage = "Starting export...";

            var progress = new Progress<ExportProgressEventArgs>(args =>
            {
                StatusMessage = args.Message;
            });

            var result = await _exportService.ExportLibraryAsync(
                CurrentLibrary, outputPath, startFrame, endFrame, progress);

            if (result.Success)
            {
                StatusMessage = $"Export completed: {result.ProcessedFrames} frames in {result.ElapsedTime.TotalSeconds:F1}s";
                _logger.LogInformation("Export completed successfully");
            }
            else
            {
                StatusMessage = $"Export failed: {result.Message}";
                _logger.LogError("Export failed: {Message}", result.Message);
            }
        }
        catch (Exception ex)
        {
            StatusMessage = $"Export error: {ex.Message}";
            _logger.LogError(ex, "Export failed with exception");
        }
        finally
        {
            IsExporting = false;
        }
    }

    public async Task SaveLibraryAsync(string filePath, bool isReference)
    {
        if (CurrentLibrary == null)
        {
            StatusMessage = "No library to save.";
            return;
        }

        try
        {
            StatusMessage = "Saving library...";
            await _libraryManager.SaveLibraryAsync(filePath, CurrentLibrary, isReference);
            StatusMessage = "Library saved successfully.";
            _logger.LogInformation("Successfully saved library: {FilePath}", filePath);
        }
        catch (Exception ex)
        {
            StatusMessage = $"Error saving library: {ex.Message}";
            _logger.LogError(ex, "Error saving library: {FilePath}", filePath);
        }
    }

    #endregion

    #region Private Methods

    private void UpdateCurrentFrame()
    {
        UpdateCurrentFrameData();
    }

    private void UpdateCurrentFrameData()
    {
        try
        {
            if (CurrentLibrary == null || CurrentFrame < 0 || CurrentFrame >= CurrentLibrary.Frames.Count)
            {
                CurrentFrameData = null;
                return;
            }

            var frame = CurrentLibrary.Frames[CurrentFrame];
            var frameData = new FrameData
            {
                Index = frame.Index,
                Image = ShowRefImage ? frame.Image : null,
                OffsetX = frame.OffsetX,
                OffsetY = frame.OffsetY,
                Transform = frame.Transform, // This was the missing piece
                Mesh = CurrentMesh
            };

            if (ShowHandImage && HandLibrary != null && CurrentFrame < HandLibrary.Frames.Count)
            {
                var handFrame = HandLibrary.Frames[CurrentFrame];
                frameData.HandImage = BlankHandImage ? null : handFrame.Image;
                frameData.HandOffsetX = handFrame.OffsetX;
                frameData.HandOffsetY = handFrame.OffsetY;
            }

            CurrentFrameData = frameData;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update current frame data");
            StatusMessage = $"Update error: {ex.Message}";
        }
    }

    #endregion

    #region Events


    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    #endregion
}
